package com.anlogic.sdk.app.ui;

import java.util.ArrayList;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Text;

import com.anlogic.sdk.utils.EnvUtils;
import com.anlogic.sdk.utils.FileUtils;
import com.anlogic.sdk.utils.StringUtils;
import com.anlogic.sdk.utils.options.BitWidth;
import com.anlogic.sdk.utils.options.ChipType;
import com.anlogic.sdk.utils.options.LanguageType;
import com.anlogic.sdk.utils.options.OsType;

import com.anlogic.sdk.app.model.ApplicationModel;
import com.anlogic.sdk.bsp.utils.PlatformUtils;
import com.anlogic.sdk.tools.IBspTool;
import com.anlogic.sdk.tools.utils.ToolsUtils;
import com.anlogic.sdk.bsp.model.IPlatformProject;

public class NewApplicationProjectWizardPage extends WizardPage {
	private Text projectNameText;
	private Button useDefaultLocButton;
	private Text locationText;
	private Button locationBrowse;
	
	private Group targetHardware;
	private Group targetSoftware;
	
	private Button createLinuxButton;
	private Combo chipCombo;
	
	private Button cLanguageButton;
	private Button cppLanguageButton;
	
	private Button managedBuildOn;
	private Combo bitWidthCombo;
	private Combo bspCombo;
	
	private List appList;
	private Text appDesc;

	private ApplicationModel model;
	
	private IBspTool bspTool;
	
	private String extraLibs;

	public NewApplicationProjectWizardPage() {
		super("wizardPage");
		setTitle("New Application Projet");
		setDescription("This wizard creates a new application project.");
		this.model = new ApplicationModel();
		this.bspTool = ToolsUtils.getBspTool();
	}

	@Override
	public void createControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NULL);
		container.setLayout(new GridLayout(3, false));

		Label projectNameLabel = new Label(container, SWT.LEFT);
		projectNameLabel.setText("Project Name:");
		projectNameText = new Text(container, SWT.BORDER | SWT.SINGLE);
		projectNameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
		
		useDefaultLocButton = new Button(container, SWT.CHECK);
		useDefaultLocButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1));
		useDefaultLocButton.setText("Use default Location");
		useDefaultLocButton.setSelection(true);
		
		Label locationLabel = new Label(container, SWT.LEFT);
		locationLabel.setText("Location:");
		locationText = new Text(container, SWT.BORDER | SWT.SINGLE);
		locationText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
		locationText.setText(EnvUtils.getWorkspacePath());
		locationText.setEnabled(false);
		locationBrowse = new Button(container, SWT.PUSH);
		locationBrowse.setText("Browse");
		locationBrowse.setEnabled(false);
		
		createLinuxButton = new Button(container, SWT.CHECK);
		createLinuxButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
		createLinuxButton.setText("CreateLinuxApp");
		createLinuxButton.setSelection(false);
		
		targetHardware = new Group(container, SWT.NULL);
		targetHardware.setText("Target Hardware");
		targetHardware.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
		targetHardware.setLayout(new GridLayout(3, false));
		
		targetSoftware = new Group(container, SWT.NULL);
		targetSoftware.setText("Target Software");
		targetSoftware.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
		targetSoftware.setLayout(new GridLayout(3, false));
		
		Label languageLabel = new Label(targetSoftware, SWT.LEFT);
		languageLabel.setText("Language:");
		cLanguageButton = new Button(targetSoftware, SWT.RADIO);
		cLanguageButton.setText(LanguageType.C.getName());
		cppLanguageButton = new Button(targetSoftware, SWT.RADIO);
		cppLanguageButton.setText(LanguageType.CPP.getName());
		cLanguageButton.setSelection(true);
		model.setLang(LanguageType.C.getName());
		
		Label bitWidthLabel = new Label(targetSoftware, SWT.LEFT);
		bitWidthLabel.setText("Bit Width:");
		bitWidthCombo = new Combo(targetSoftware, SWT.POP_UP);
		GridDataFactory.swtDefaults().span(2, 1).applyTo((Control) bitWidthCombo);

		Composite appComp = new Composite(container, SWT.NULL);
		GridDataFactory.swtDefaults().span(3, 1).grab(true, true).applyTo((Control) appComp);
		appComp.setLayout(new GridLayout(2, true));
		
		Label appNameLabel = new Label(appComp, SWT.LEFT);
		appNameLabel.setText("Template List:");
		Label appDescLabel = new Label(appComp, SWT.LEFT);
		appDescLabel.setText("Template Description:");
		
		GridData appGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
		appGridData.widthHint = 300;
		appGridData.heightHint = 300;
		appList = new List(appComp, SWT.BORDER | SWT.V_SCROLL);
		appList.setLayoutData(appGridData);
		appDesc = new Text(appComp, SWT.BORDER | SWT.V_SCROLL | SWT.WRAP | SWT.MULTI | SWT.READ_ONLY);
		appDesc.setLayoutData(appGridData);
		
		updateTargetHardware(createLinuxButton.getSelection());
		
		addListener();

		validatePage();

		setControl(container);
	}

	public void updateTargetHardware(boolean createLinux) {
	    for (Control child : targetHardware.getChildren()) {
	        child.dispose();
	    }
	    
		if (createLinux) {
			Label chipLabel = new Label(targetHardware, SWT.LEFT);
			chipLabel.setText("Chip Type:"); 
			chipCombo = new Combo(targetHardware, SWT.POP_UP);
			chipCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
			chipCombo.setItems(ChipType.linuxSupported());
			chipCombo.select(0);
			
			chipCombo.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent event) {
					chipChanged(chipCombo.getText());
					updateApps();
					validatePage();
				}
			});
		} else {
			Label bspLabel = new Label(targetHardware, SWT.NULL);
			bspLabel.setText("Platform:");
			bspCombo = new Combo(targetHardware, SWT.POP_UP);
			bspCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
			java.util.List<IPlatformProject> platformProjectsInWorkspace = PlatformUtils.getPlatformProjectsInWorkspace();
			int size = platformProjectsInWorkspace.size();
			if (size == 0) {
				bspCombo.add("None");
			} else {
				for (int i = 0; i < size; i++) {
					bspCombo.add(platformProjectsInWorkspace.get(i).getName());
				}
			}
			bspCombo.select(0);
			
			managedBuildOn = new Button(targetHardware, SWT.CHECK);
			managedBuildOn.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1));
			managedBuildOn.setText("ManagedBuildOn");
			managedBuildOn.setSelection(false);
			
			managedBuildOn.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent e) {
					model.setManagedBuildOn(managedBuildOn.getSelection());
				}
			});
			
			bspCombo.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent event) {
					bspChanged(bspCombo.getItem(bspCombo.getSelectionIndex()));
					validatePage();
				}
			});
			
			
			bspChanged(bspCombo.getText());
		}
		targetHardware.layout(true, true);
		
		updateLinuxApp(createLinux);
	}
	
	public void addListener() {
		projectNameText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});
		locationText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validatePage();
			}
		});
		useDefaultLocButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				locationText.setEnabled(!useDefaultLocButton.getSelection());
				locationBrowse.setEnabled(!useDefaultLocButton.getSelection());
				validatePage();
			}
		});

		locationBrowse.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN);
				String result = dialog.open();
				if (result != null && !result.isEmpty()) {
					locationText.setText(result);
				}
			}
		});
		
		cLanguageButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				model.setLang(LanguageType.C.getName());
				validatePage();
			}
		});
		
		cppLanguageButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				model.setLang(LanguageType.CPP.getName());
				validatePage();
			}
		});
		
		bitWidthCombo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				model.setBitWidth(bitWidthCombo.getItem(bitWidthCombo.getSelectionIndex()));
				updateApps();
				validatePage();
			}
		});

		createLinuxButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				updateTargetHardware(createLinuxButton.getSelection());
				updateLinuxApp(createLinuxButton.getSelection());
				updateApps();
				validatePage();
			}
		});
		
		appList.addSelectionListener((SelectionListener) new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				appModified();
				validatePage();
			}
		});
	}

	protected void appModified() {
		int index = appList.getSelectionIndex();
		if (index != -1) {
			String appName = appList.getItem(index);
			model.setAppName(appName);
			appDesc.setText(bspTool.getAppDesc(appName));
		} else {
			model.setAppName("");
			appDesc.setText("");
		}
		
		if (!OsType.isLinux(model.getOs())) {
			java.util.List<String> extraLibList = bspTool.getAppExtraLibs(model.getPlatform().getMssPath(), model.getAppName());
			if (!extraLibList.isEmpty()) {
				extraLibs = StringUtils.getCSVString(extraLibList);
			} else {
				extraLibs = "";
			}
		} else {
			extraLibs = "";
		}
	}

	public void updateApps() {
		String bspName = model.getBspName();
		String os = model.getOs();
		if (!OsType.isLinux(os) && (bspName == null || bspName.equals("None"))) {
			return;
		}
		
		java.util.List<String> appNames;
		
		if (OsType.isLinux(os)) {
			appNames = bspTool.getLinuxAppNames(model.getChip(), model.getProc());
		} else {
			appNames = new ArrayList<String>(bspTool.getAppNames(model.getOs().toLowerCase(), model.getChip(), model.getProc()));
			String bitWidth = model.getBitWidth();
			if (bitWidth.equals(BitWidth.BIT32.getName()) && appNames.contains("FSBL")) {
				appNames.remove(appNames.indexOf("FSBL"));
			}
		}
		
		int id = appNames.indexOf("EMPTY");
		id = id == -1 ? 0 : id;
		String[] appItems = appNames.toArray(new String[0]);
		appList.setItems(appItems);
		appList.select(id);
		
		appModified();
	}

	private boolean validatePage() {
		if (!validateBSP()) {
			setPageComplete(false);
			return false;
		}
		
		if (!validateApp()) {
			setPageComplete(false);
			return false;
		}
		
		if (!validateProject()) {
			setPageComplete(false);
			return false;
		}

		if (!validateLocation()) {
			setPageComplete(false);
			return false;
		}
		
		setMessage(null);
		setErrorMessage(null);
		
		setPageComplete(true);

		return true;
	}

	private boolean validateProject() {
		String projName = projectNameText.getText();
		if (projName == null || projName.length() == 0) {
			setErrorMessage("Project Name must be specified");
			return false;
		}
		if (!FileUtils.checkFileNameLegality(projName)) {
			setErrorMessage("Project name is illegal");
			return false;
		}
		IResource projectSource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(projName));
		if (projectSource != null) {
			setErrorMessage("Project has already exist!");
			return false;
		}
		model.setProjName(projName);
		return true;
	}

	private boolean validateLocation() {
		String projLoc = locationText.getText();
		if (projLoc == null || projLoc.length() == 0) {
			setErrorMessage("Project Name must be specified");
			return false;
		}
		if (!FileUtils.checkFilePathLegality(projLoc)) {
			setErrorMessage("Project location is illegal");
			return false;
		}
		projLoc = FileUtils.convertToLinuxPath(projLoc);
		IPath projLocPath = Path.fromPortableString(projLoc).append(projectNameText.getText());
		model.setProjLoc(projLocPath.toString());
		return true;
	}

	private boolean validateBSP() {
		if (createLinuxButton.getSelection()) {
			return true;
		}
		String bspName = bspCombo.getText();
		if (bspName.equals("None") && !createLinuxButton.getSelection()) {
			setErrorMessage("BSP must be specified, pleate create a Platform Project.");
			return false;
		}
		
		bspChanged(bspName);
		return true;
	}
	
	private boolean validateApp() {
		if (bspTool.getChip() == null) {
			setErrorMessage("BSP must be specified, pleate create a Platform Project.");
			return false;
		}
		if (appList.getItemCount() == 0) {
			setErrorMessage("This BSP does not have an application template.");
			return false;
		}
		if (extraLibs != null && !extraLibs.isEmpty()) {
			String extraLibStr = extraLibs.replace(",", "\n");
			setErrorMessage(String.format("This application requires \n%s\n library or driver in the Platform Project.", extraLibStr));
			return false;
		}
		return true;
	}

	private void bspChanged(String bspName) {
		if (bspName.equals("None")) {
			return;
		}
		if (bspName.equals(model.getBspName())) {
			return;
		}
		IPlatformProject platformProject = PlatformUtils.getPlatformProject(bspName);
		String chip = platformProject.getChip();
		String os = platformProject.getOs();
		model.setBspName(bspName);
		model.setPlatform(platformProject);
		bspTool.setChip(chip);
		updateBitWidth(chip, os);
		updateApps();
	}
	
	private void updateBitWidth(String chip, String os) {
		String[] bitWidthList = ChipType.getBitWidthList(chip, os).toArray(new String[0]);
		if (bitWidthList.length > 0) {
			bitWidthCombo.setItems(bitWidthList);
			bitWidthCombo.select(0);
			model.setBitWidth(bitWidthCombo.getText());
		}
		
		if (bitWidthList.length > 1) {
			bitWidthCombo.setEnabled(true);
		} else {
			bitWidthCombo.setEnabled(false);
		}
	}
	
	private void updateLinuxApp(boolean enabled) {
		if (enabled) {
			model.setOs(OsType.Linux.getName());
			model.setManagedBuildOn(true);
			chipChanged(chipCombo.getText());
		} else {
			if (model.getPlatform() == null) {
				return;
			}
			if (model.getPlatform().getChip() == null) {
				return;
			}
			if (model.getPlatform().getOs() != null) {
				model.setOs(model.getPlatform().getOs());
			} else {
				model.setOs(OsType.Standalone.getName());
			}
			model.setChip(model.getPlatform().getChip());
			model.setManagedBuildOn(managedBuildOn.getSelection());
			updateBitWidth(model.getChip(), model.getOs());
		}
	}
	
	private void chipChanged(String chip) {
		model.setChip(chip);
		bspTool.setChip(chip);
		model.setProc(ChipType.getCpuList(chip).get(0).getName());
		updateBitWidth(chip, OsType.Linux.getName());
	}
	
	public ApplicationModel getModel() {
		return model;
	}
}